/* Copyright (C) 2011 clueless <clueless.mmopeon@gmail.com>
 *
 * This file is part of MMO Peon.
 *
 * MMO Peon is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MMO Peon is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MMO Peon.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <map>
#include "objectmap.h"
#include <windows.h>
#include <cmath>
#include <cstdint>
#include <vector>

HANDLE objectMapMutex;
ObjectMapData objectData;

static ObjectMapData *ObjectMapObtain();
static void ObjectMapRelease();


bool ObjectMapInit()
{
    objectMapMutex = CreateMutex(NULL, false, NULL);
    if (!objectMapMutex)
        return false;

    return true;
}

void ObjectMapFree()
{
    CloseHandle(objectMapMutex);
}

static ObjectMapData *ObjectMapObtain()
{
    WaitForSingleObject(objectMapMutex, INFINITE);
    return &objectData;
}

static void ObjectMapRelease()
{
    ReleaseMutex(objectMapMutex);
}


ObjectMap::ObjectMap(bool obtain)
{
    obtained = obtain;
    if (obtain)
        data = ObjectMapObtain();
    else
        data = new ObjectMapData;
}

ObjectMap::ObjectMap(const ObjectMap &source)
{
    obtained = false;
    data = new ObjectMapData(*source.data);
}

ObjectMap& ObjectMap::operator=(const ObjectMap& source)
{
    if (this != &source)
    {
        if (obtained)
        {
            ObjectMapRelease();
            data = new ObjectMapData(*source.data);
        }
        else
            *data = *source.data;
    }
    return *this;
}

ObjectMap::~ObjectMap()
{
    if (obtained)
        ObjectMapRelease();
    else
        delete data;
}

size_t ObjectMap::Count() const
{
    return data->size();
}

bool ObjectMap::HasObject(uint32_t objectId) const
{
    if (data->count(objectId))
       return true;
    else
        return false;
}

void ObjectMap::Delete(uint32_t objectId)
{
    data->erase(objectId);
}

void ObjectMap::Update(const GameObject &object)
{
    (*data)[object.objectId] = object;
}

void ObjectMap::Add(const GameObject &object)
{
    (*data)[object.objectId] = object;
}

GameObject *ObjectMap::Get(uint32_t objectId)
{
    return &(*data)[objectId];
}

ObjectMap ObjectMap::Filter(uint32_t objectType) const
{
    ObjectMap filtered;

    for (auto it = data->begin(); it != data->end(); it++)
        if (it->second.objectType == objectType)
            filtered.Add(it->second);

    return filtered;
}

ObjectMap ObjectMap::Filter(float distance, const RomCoords& source) const
{
    ObjectMap filtered;

    for (auto it = data->begin(); it != data->end(); it++)
        if (it->second.coords.Distance(source) < distance)
            filtered.Add(it->second);

    return filtered;
}

ObjectMapData::iterator ObjectMap::Begin()
{
    return data->begin();
}

ObjectMapData::iterator ObjectMap::End()
{
    return data->end();
}
